using IQIGame.Onigao.Framework;
using System.Collections.Generic;

namespace IQIGame.Onigao.Game
{
    public class ConfigurableFSM : IReusableClass
    {
        public int currentStateId { get; protected set; }
        public BaseCFSMState currentState { get; protected set; }
        public bool isStarted => currentState != null;
        public bool isActive { protected set; get; }
        public int Count => _states.Count;
        public uint MaxStore => 50;
        public ICFSMEntity entity { get; private set; }
        public CFSMData data { get; private set; }
        public HashSet<string> triggerData { get; private set; } = new HashSet<string>();

        private Dictionary<int, CFSMCondition> _conditions = new Dictionary<int, CFSMCondition>();
        private Dictionary<int, BaseCFSMState> _states = new Dictionary<int, BaseCFSMState>();
        private BaseCFSMState entryState;

        public void Init(CFSMConfig config, ICFSMEntity entity)
        {
            this.entity = entity;
            foreach (CFSMConditionCfg cfgCondition in config.conditions)
            {
                CFSMCondition cond = ClassPool.Get<CFSMCondition>();
                cond.Init(this, config.name, cfgCondition);
                if (_conditions.ContainsKey(cond.id))
                {
                    LogGame.LogError("重复添加条件:" + cond.id);
                    continue;
                }
                _conditions.Add(cond.id, cond);
            }
            for (int i = 0; i < config.states.Count; i++)
            {
                CFSMStateCfg cfgState = config.states[i];
                BaseCFSMState state = CFStateMachineManager.Instance.blackboard.CreateState(config.name, cfgState.name);
                state.Init(this, cfgState);
                if (_states.ContainsKey(state.id))
                {
                    LogGame.LogError("重复添加状态:" + state.id);
                    continue;
                }
                _states.Add(state.id, state);

                if (i == 0)
                {
                    entryState = state;
                }
            }
        }

        public void Start()
        {
            if (entryState == null)
            {
                LogGame.LogError("找不到初始状态。");
                return;
            }

            if (currentState != null)
            {
                return;
            }

            isActive = true;
            ChangeState(entryState.id);
        }

        public void Restart()
        {
            if (!isActive)
            {
                return;
            }
            data?.Clear();
            triggerData.Clear();
            ChangeState(entryState.id);
        }

        public BaseCFSMState GetState(int id)
        {
            if (_states.TryGetValue(id, out var state))
            {
                return state;
            }
            return null;
        }

        public CFSMCondition GetCondition(int id)
        {
            if (_conditions.TryGetValue(id, out var condition))
            {
                return condition;
            }
            return null;
        }

        public void Stop()
        {
            if (this.currentState == null)
            {
                return;
            }

            currentState.active = false;
            currentState.OnExit();

            currentStateId = 0;
            currentState = null;
            isActive = false;
        }

        public void ChangeState(int stateId)
        {
            if (!isActive)
            {
                LogGame.LogError("[FSMSystem|ChangeState] fsm not start or not active");
                return;
            }
            if (stateId == currentStateId)
            {
                return;
            }
            if (!_states.TryGetValue(stateId, out var nextState))
            {
                LogGame.LogError("找不到状态：" + stateId);
                return;
            }

            var oldState = currentState;
            if (oldState != null)
            {
                oldState.active = false;
                oldState.OnExit();
            }
            triggerData.Clear();
            currentState = nextState;
            currentStateId = stateId;
            currentState.active = true;
            currentState.OnEnter(oldState == null ? -1 : oldState.id);
        }

        public virtual void Update(float deltaTime)
        {
            if (isActive && entity.isFsmAvailable)
            {
                currentState?.Update(deltaTime);
            }
        }

        public virtual bool TryGetState<T>(int stateId, out T result) where T : BaseCFSMState
        {
            if (_states.TryGetValue(stateId, out var value))
            {
                result = value as T;
                return result != null;
            }
            result = default(T);
            return false;
        }

        public void SetData(CFSMData data)
        {
            this.data = data;
        }

        public void SetTrigger(string key)
        {
            triggerData.Add(key);
        }

        public void OnReset()
        {
            Stop();
            foreach (var kv in _states)
            {
                ClassPool.PutAutoType(kv.Value);
            }
            _states.Clear();
            foreach (var kv in _conditions)
            {
                ClassPool.PutAutoType(kv.Value);
            }
            _conditions.Clear();
            triggerData.Clear();
            entity = null;
            data = null;
            entryState = null;
            isActive = false;
        }
    }
}
